package com.wkbb.basic.thread;

import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.wkbb.basic.model.Family;
import com.wkbb.basic.service.ClassInfoService;
import com.wkbb.basic.service.FamilyService;
import com.wkbb.basic.service.XmppService;
import com.wkbb.common.constants.RedisKeyConstant;
import com.wkbb.common.dto.ResultDTO;
import com.wkbb.common.dto.basic.FamilyInfoDto;
import com.wkbb.common.dto.basic.StudentInfoDto;
import com.wkbb.common.enums.RoleTypeEnum;
import com.wkbb.common.redis.RedisTemplateUtil;
import com.wkbb.common.utils.BeanUtil;
import com.wkbb.common.utils.ThreadPoolUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.concurrent.FutureTask;
import java.util.concurrent.RejectedExecutionException;
import java.util.stream.Collectors;

import static com.wkbb.common.constants.RedisKeyConstant.WKBB_BASIC_IMPORT_RESULT;

/**
 * @author yangdaofang
 * 创建时间：2020-08-14 16:49
 */
@Component
@Slf4j
public class BasicSetImportResultTask {

    @Autowired
    @Lazy
    private XmppService xmppService;

    @Autowired
    private RedisTemplateUtil redisTemplateUtil;

    @Autowired
    private FamilyService familyService;

    @Autowired
    private ClassInfoService classInfoService;


    @Async
    public void setImportResult(String orderNo, List<FutureTask<ResultDTO<Map<String, Object>>>> futureTaskList, Long orgId, Date date) throws RejectedExecutionException {
        try {

            //同步集中获取处理结果
            Integer importOkNum = 0;
            long startTime = System.currentTimeMillis();
            boolean isNeedForceCancel = false;//是否需要强制取消其他线程
            Set<StudentInfoDto> totalFailList = new HashSet();
            if (futureTaskList.size() > 0) {
                ResultDTO<Map<String, Object>> resultDto;

                int taskNum = 0; //已经完成的任务数量

                ListIterator<FutureTask<ResultDTO<Map<String, Object>>>> it = futureTaskList.listIterator();
                while (true) {
                    it = futureTaskList.listIterator();
                    while (it.hasNext()) {
                        FutureTask<ResultDTO<Map<String, Object>>> futureTask = it.next();
                        if ((System.currentTimeMillis() - startTime) > 2400000) {//超过40分钟，就取消未完成的任务 40*60*1000
                            isNeedForceCancel = true;
                        }
                        if (isNeedForceCancel) {
                            try {
                                if (!futureTask.isDone() && !futureTask.isCancelled()) {//只取消 未完成 并且 不是已经被取消的
                                    Boolean isCanceled = futureTask.cancel(true);
                                    it.remove();//取消线程后，从缓存清除，进行下一次循环继续取结果
                                    futureTaskList.remove(futureTask);
                                    //取不到被取消的线程里面的数据，没办法做错误提示，那么把所有线程都取消，超过20分钟还执行不完那么其他线程也会超时。
                                    log.info("----批量导入学生,家长----超过40分钟，强制取消其他未完成的任务--isCanceled:{}", isCanceled);
                                }
                            } catch (Exception e) {
                                log.error("----批量导入学生,家长----超过40分钟，强制取消其他未完成的任务--取消任务异常..msg:{}", e.getMessage());
                            }
                            continue;
                        }

                        if (futureTask.isDone() && !futureTask.isCancelled()) {//执行成功，并且不是被取消的
                            taskNum++;
                            log.info("----批量导入学生,家长----第{}个线程处理完毕--", taskNum);
                            it.remove();//拿到结果后，从缓存清除，进行下一次循环继续取结果
                            futureTaskList.remove(futureTask);

                            try {
                                resultDto = futureTask.get();//会造成线程阻塞等待
                                if (null == resultDto || !resultDto.isSuccess()) {//处理失败，将其他线程取消，然后退出
                                    isNeedForceCancel = true;
                                    //                                return new ResultDTO(resultDto.isSuccess(), resultDto.getErrorCode(), resultDto.getErrorMsg());
                                }

                                Map<String, Object> result = resultDto.getData();
                                //log.info("----批量导入学生,家长,FutureTask返回的oriResult------{}", JSONObject.toJSONString(result));
                                List<StudentInfoDto> okList = (List<StudentInfoDto>) result.get("success");
                                List<StudentInfoDto> failList = (List<StudentInfoDto>) result.get("fail");
                                importOkNum = importOkNum + okList.size();
                                totalFailList.addAll(failList);

                            } catch (Exception e) {
                                log.error("----批量导入学生,家长----获取线程处理结果 异常..msg:{}", e.getMessage());
                                e.printStackTrace();
                            }
                        }
                    }
                    if (futureTaskList.size() == 0) {
                        log.info("----批量导入学生,家长----所有线程处理完毕--退出循环");
                        break;
                    }

                    if (isNeedForceCancel) {
                        //被强制取消，处理完所有线程后，再返回给用户界面提示异常
                        Map<String, Object> returnMap = new HashMap();
                        returnMap.put("importOkNum", importOkNum);
                        returnMap.put("importFailList", totalFailList);
                    }
                    //                log.debug("----批量导入学生,家长----等待200ms重试获取线程执行结果--");
                    Thread.sleep(100L);

                }
            }

            /******************************IM相关开始***************************************/
            //防sql 1S时间计算误差
            date = new Date(date.getTime() - 1000);
            familyService.getRepairFamilyList(orgId);
            /****************************IM相关结束***************************************/
            //1教师 2家长 3学生 4职员 5游客"

            /*****************************导入用户XMPP统一处理开始***************************************/
            ThreadPoolUtil.addPoolTask(new XmppUpdatePersonByDateTask(orgId, date, xmppService, RoleTypeEnum.STUDENT.getValue()));
            /*****************************导入用户XMPP统一处理结束***************************************/
            if (totalFailList.size() > 0){
                throw new RejectedExecutionException(JSONObject.toJSONString(totalFailList));
            }
            log.info("----批量导入学生,家长,最终导入结果---totalFailList={}", JSONObject.toJSONString(totalFailList));
            //序列化字段
            ObjectMapper mapper = new ObjectMapper();
            mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
            String outJson = mapper.writeValueAsString(totalFailList);
            log.info("----批量导入学生,家长,最终成功导入{}条数据----", importOkNum);
//            log.info("----批量导入学生,家长,最终导入totalFailList结果,Json格式:---{}",outJson);

            Map<String, Object> returnMap = new HashMap();
            returnMap.put("importOkNum", importOkNum);
            returnMap.put("importFailList", totalFailList);

            //数据存在redis里面去
            redisTemplateUtil.set(WKBB_BASIC_IMPORT_RESULT + orderNo, returnMap);
            log.info("----批量导入学生,家长,导入结果存入redis,key:{},value:{}", WKBB_BASIC_IMPORT_RESULT + orderNo, JSONObject.toJSONString(returnMap));

            //清除学校导入的redis
            redisTemplateUtil.delete(RedisKeyConstant.WKBB_SYSTEM + "importExcelFile:" +"redis:"+"orgId:" + orgId);
        } catch (
                RejectedExecutionException e) {
            log.error("----批量导入学生,家长----异步获取导入结果异常..msg:{}", e.getMessage());
            throw new RejectedExecutionException(e);
        } catch (Exception e) {
            log.error("----批量导入学生,家长----异步获取导入结果异常..msg:{}", e.getMessage());
        }
    }

}
